﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Xml;

namespace DevelopTool.Common
{
    /// <summary>
    /// XML帮助类
    /// </summary>
    public static class XmlHelper
    {
        #region 生成实体类

        /// <summary>
        /// 根据XML字符串生成实体类
        /// </summary>
        /// <param name="xmlContent">XML字符串内容</param>
        /// <returns>生成的实体类的C#代码</returns>
        public static string GenerateEntitiesFromXml(string xmlContent)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlContent);

            StringBuilder codeBuilder = new StringBuilder();
            codeBuilder.AppendLine("using System;");
            codeBuilder.AppendLine("using System.Collections.Generic;");
            codeBuilder.AppendLine();

            GenerateClassCode(xmlDoc.DocumentElement, codeBuilder, new HashSet<string>());

            return codeBuilder.ToString();
        }

        /// <summary>
        /// 递归生成每个XML节点对应的类代码
        /// </summary>
        /// <param name="node">XML节点</param>
        /// <param name="codeBuilder">用于构建代码的StringBuilder</param>
        /// <param name="generatedClasses">已生成的类名集合，用于避免重复生成类</param>
        private static void GenerateClassCode(XmlNode node, StringBuilder codeBuilder, HashSet<string> generatedClasses)
        {
            string className = NormalizeClassName(node.Name);

            if (!generatedClasses.Contains(className))
            {
                generatedClasses.Add(className);

                codeBuilder.AppendLine($"/// <summary>");
                codeBuilder.AppendLine($"/// Represents the {node.Name} element.");
                codeBuilder.AppendLine($"/// </summary>");
                codeBuilder.AppendLine($"public class {className}");
                codeBuilder.AppendLine("{");

                foreach (XmlAttribute attribute in node.Attributes)
                {
                    string propertyName = NormalizePropertyName(attribute.Name);
                    string propertyType = DeterminePropertyType(attribute.Value);
                    codeBuilder.AppendLine($"    /// <summary>");
                    codeBuilder.AppendLine($"    /// Gets or sets the {attribute.Name} attribute.");
                    codeBuilder.AppendLine($"    /// </summary>");
                    codeBuilder.AppendLine($"    public {propertyType} {propertyName} {{ get; set; }}");
                }

                var childNodeGroups = GroupChildNodesByName(node);

                foreach (var group in childNodeGroups)
                {
                    XmlNode childNode = group[0];
                    string propertyName = NormalizePropertyName(childNode.Name);
                    string propertyType = NormalizeClassName(childNode.Name); // 默认子节点对应的类名

                    if (childNode.Attributes.Count == 0 && childNode.ChildNodes.Count == 1 && childNode.FirstChild.NodeType == XmlNodeType.Text)
                    {
                        // 如果子节点只有一个文本节点，则将其视为简单类型
                        propertyType = DeterminePropertyType(childNode.InnerText);
                    }
                    else
                    {
                        GenerateClassCode(childNode, codeBuilder, generatedClasses);
                    }

                    if (group.Count > 1)
                    {
                        propertyType = $"List<{propertyType}>";
                    }

                    codeBuilder.AppendLine($"    /// <summary>");
                    codeBuilder.AppendLine($"    /// Gets or sets the {childNode.Name} element.");
                    codeBuilder.AppendLine($"    /// </summary>");
                    codeBuilder.AppendLine($"    public {propertyType} {propertyName} {{ get; set; }}");
                }

                codeBuilder.AppendLine("}");
                codeBuilder.AppendLine();
            }
        }

        /// <summary>
        /// 确定属性的C#数据类型
        /// </summary>
        /// <param name="value">属性值</param>
        /// <returns>属性的C#数据类型</returns>
        private static string DeterminePropertyType(string value)
        {
            if (int.TryParse(value, out _))
            {
                return "int";
            }
            if (float.TryParse(value, out _))
            {
                return "float";
            }
            if (bool.TryParse(value, out _))
            {
                return "bool";
            }
            if (DateTime.TryParse(value, out _))
            {
                return "DateTime";
            }
            if (decimal.TryParse(value, out _))
            {
                return "decimal";
            }
            if (double.TryParse(value, out _))
            {
                return "double";
            }
            return "string";
        }

        /// <summary>
        /// 规范化类名（将节点名转换为Pascal命名法）
        /// </summary>
        /// <param name="name">节点名</param>
        /// <returns>规范化后的类名</returns>
        private static string NormalizeClassName(string name)
        {
            return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(name.Replace("_", " ")).Replace(" ", "");
        }

        /// <summary>
        /// 规范化属性名（将属性名转换为Pascal命名法）
        /// </summary>
        /// <param name="name">属性名</param>
        /// <returns>规范化后的属性名</returns>
        private static string NormalizePropertyName(string name)
        {
            return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(name.Replace("_", " ").Replace("-", " ")).Replace(" ", "");
        }

        /// <summary>
        /// 按名称分组子节点
        /// </summary>
        /// <param name="node">XML节点</param>
        /// <returns>按名称分组的子节点列表</returns>
        private static List<List<XmlNode>> GroupChildNodesByName(XmlNode node)
        {
            var groups = new Dictionary<string, List<XmlNode>>();

            foreach (XmlNode childNode in node.ChildNodes)
            {
                if (childNode.NodeType == XmlNodeType.Element)
                {
                    if (!groups.ContainsKey(childNode.Name))
                    {
                        groups[childNode.Name] = new List<XmlNode>();
                    }
                    groups[childNode.Name].Add(childNode);
                }
            }

            return new List<List<XmlNode>>(groups.Values);
        }

        #endregion 生成实体类
    }
}
